
#include "bmp.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QMessageBox>

Bmp::Bmp(QFile *image)
{
    QDataStream imgStream(image);
    imgStream.setByteOrder(QDataStream::LittleEndian);

    uint storage;        //for read DWORD type infomation

    //读取文件头
    imgStream >> bf.bfType;

    imgStream >> storage;
    bf.bfSize = storage;

    imgStream >> bf.bfReserved1;
    imgStream >> bf.bfReserved2;

    imgStream >> storage;
    bf.bfOffBits = storage;

    //读取信息头
    imgStream >> storage;
    bi.biSize = storage;

    imgStream >> storage;
    bi.biWidth = storage;

    imgStream >> storage;
    bi.biHeight = storage;

    imgStream >> bi.biPlanes;
    imgStream >> bi.biBitCount;

    imgStream >> storage;
    bi.biCompression = storage;

    imgStream >> storage;
    bi.biSizeImage = storage;

    imgStream >> storage;
    bi.biXPelsPerMeter = storage;

    imgStream >> storage;
    bi.biYPelsPerMeter = storage;

    imgStream >> storage;
    bi.biClrUsed = storage;

    imgStream >> storage;
    bi.biClrImportant = storage;

    //读取图片信息
    rgb = new uchar* [bi.biWidth * bi.biHeight];
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        rgb[i] = new uchar[3];
    }

    image->seek(bf.bfOffBits);
    QDataStream rgbStream(image);
    rgbStream.setByteOrder(QDataStream::LittleEndian);
    uint dataSize_rgb = bi.biWidth * bi.biHeight * 3;
    uchar *temp_rgb = new uchar[dataSize_rgb];
    for (uint i = 0; i < dataSize_rgb; i++)
    {
        rgbStream >> temp_rgb[i];
    }

    uchar *p = temp_rgb;
    for (int y = 0; y < bi.biHeight; y++)
    {
        for (int x = 0; x < bi.biWidth; x++)
        {
            for (int i = 0; i < 3; i++)
            {
                rgb[x + y * bi.biWidth][i] = *p;
                p++;
            }

            if (x == bi.biWidth - 1)
            {
                for (int j = 0; j < bi.biWidth % 4; j++)
                {
                    p++;
                }
            }
        }
    }
}

Bmp::Bmp(Bmp &bmp)
{
    bf = bmp.bf;
    bi = bmp.bi;

    rgb = new uchar* [bi.biWidth * bi.biHeight];
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        rgb[i] = new uchar[3];
    }

    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            rgb[i][j] = bmp.rgb[i][j];
        }
    }
}

Bmp::~Bmp()
{
    delete[] rgb;
}

bool Bmp::save(QString saveLocation)
{
    QFile saveFile(saveLocation);
    if (!saveFile.open(QFile::WriteOnly))
    {
        return false;
    }

    //save functions
    QDataStream imgStream(&saveFile);
    imgStream.setByteOrder(QDataStream::LittleEndian);

    uint storage;        //for write DWORD type infomation

    //保存文件头
    imgStream << bf.bfType;

    storage = bf.bfSize;
    imgStream << storage;

    imgStream << bf.bfReserved1;
    imgStream << bf.bfReserved2;

    storage = bf.bfOffBits;
    imgStream << storage;

    //保存信息头
    storage = bi.biSize;
    imgStream << storage;

    storage = bi.biWidth;
    imgStream << storage;

    storage = bi.biHeight;
    imgStream << storage;

    imgStream << bi.biPlanes;
    imgStream << bi.biBitCount;

    storage = bi.biCompression;
    imgStream << storage;

    storage = bi.biSizeImage;
    imgStream << storage;

    storage = bi.biXPelsPerMeter;
    imgStream << storage;

    storage = bi.biYPelsPerMeter;
    imgStream << storage;

    storage = bi.biClrUsed;
    imgStream << storage;

    storage = bi.biClrImportant;
    imgStream << storage;

    //保存像素值
    saveFile.seek(bf.bfOffBits);
    QDataStream rgbStream(&saveFile);
    rgbStream.setByteOrder(QDataStream::LittleEndian);

    uint dataSize_rgb = bi.biWidth * bi.biHeight * 3 + bi.biHeight * 4;
    uchar *temp_rgb = new uchar[dataSize_rgb];
    for (uint i = 0; i < dataSize_rgb; i++)
    {
        temp_rgb[i] = 0;
    }

    uchar *p = temp_rgb;
    for (int y = 0; y < bi.biHeight; y++)
    {
        for (int x = 0; x < bi.biWidth; x++)
        {
            for (int i = 0; i < 3; i++)
            {
                *p = rgb[x + y * bi.biWidth][i];
                p++;
            }

            if (x == bi.biWidth - 1)
            {
                for (int j = 0; j < bi.biWidth % 4; j++)
                {
                    p++;
                }
            }
        }
    }
    int count = p - temp_rgb;

    for (int i = 0; i < count; i++)
    {
        rgbStream << temp_rgb[i];
    }

    return true;
}

QImage* Bmp::toQImage()
{
    QImage *myImage = new QImage(bi.biWidth, bi.biHeight, QImage::Format_RGB888);
    myImage->fill(QColor(Qt::black).rgb());

    int rgb_y = 0;
    for (int y = bi.biHeight - 1; y >= 0; y--, rgb_y++)
    {
        int rgb_x = 0;
        for (int x = 0; x < bi.biWidth; x++, rgb_x++)
        {
            int b = rgb[rgb_x + rgb_y * bi.biWidth][0];
            int g = rgb[rgb_x + rgb_y * bi.biWidth][1];
            int r = rgb[rgb_x + rgb_y * bi.biWidth][2];
            myImage->setPixel(x, y, qRgb(r, g, b));
        }
    }

    return myImage;
}

void Bmp::toGray()
{
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        double b = rgb[i][0];
        double g = rgb[i][1];
        double r = rgb[i][2];
        uchar gray = r * 0.299 + g * 0.587 + b * 0.114;
        rgb[i][0] = gray;
        rgb[i][1] = gray;
        rgb[i][2] = gray;
    }
}

void Bmp::Gausssian_blur()
{
    uchar **temp_rgb = new uchar* [bi.biWidth * bi.biHeight];
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        temp_rgb[i] = new uchar[3];
    }
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        temp_rgb[i][0] = rgb[i][0];
        temp_rgb[i][1] = rgb[i][1];
        temp_rgb[i][2] = rgb[i][2];
    }

    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        /* 0.0947416  0.118318  0.0947416
         * 0.118318   0.147761  0.118318
         * 0.0947416  0.118318  0.0947416
         */
        for(int j = 0; j < 3; j++)
        {
            //边缘镜像处理
            if (i == 0)          //左上
            {
                rgb[i][j] = (temp_rgb[i][j] + temp_rgb[i+1][j] + temp_rgb[i+bi.biWidth][j] + temp_rgb[i+bi.biWidth+1][j]) * 0.0947416
                          + (temp_rgb[i][j] + temp_rgb[i][j] + temp_rgb[i+1][j]+ temp_rgb[i+bi.biWidth][j]) * 0.118318
                          +  temp_rgb[i][j] * 0.147761;
            }
            else if (i == bi.biWidth - 1)          //右上
            {
                rgb[i][j] = (temp_rgb[i-1][j] + temp_rgb[i][j] + temp_rgb[i+bi.biWidth-1][j] + temp_rgb[i+bi.biWidth][j]) * 0.0947416
                          + (temp_rgb[i][j] + temp_rgb[i-1][j] + temp_rgb[i][j]+ temp_rgb[i+bi.biWidth][j]) * 0.118318
                          +  temp_rgb[i][j] * 0.147761;
            }
            else if (i == bi.biWidth * bi.biHeight - bi.biWidth)        //左下
            {
                rgb[i][j] = (temp_rgb[i-bi.biWidth][j] + temp_rgb[i-bi.biWidth+1][j] + temp_rgb[i][j] + temp_rgb[i+1][j]) * 0.0947416
                          + (temp_rgb[i-bi.biWidth][j] + temp_rgb[i][j] + temp_rgb[i+1][j]+ temp_rgb[i][j]) * 0.118318
                          +  temp_rgb[i][j] * 0.147761;
            }
            else if (i == bi.biWidth * bi.biHeight - 1)            //右下
            {
                rgb[i][j] = (temp_rgb[i-bi.biWidth-1][j] + temp_rgb[i-bi.biWidth][j] + temp_rgb[i-1][j] + temp_rgb[i][j]) * 0.0947416
                          + (temp_rgb[i-bi.biWidth][j] + temp_rgb[i-1][j] + temp_rgb[i][j]+ temp_rgb[i][j]) * 0.118318
                          +  temp_rgb[i][j] * 0.147761;
            }
            else if ( i < bi.biWidth)                //上边界除端点
            {
                rgb[i][j] = (temp_rgb[i-1][j] + temp_rgb[i+1][j] + temp_rgb[i+bi.biWidth-1][j] + temp_rgb[i+bi.biWidth+1][j]) * 0.0947416
                          + (temp_rgb[i][j] + temp_rgb[i-1][j] + temp_rgb[i+1][j]+ temp_rgb[i+bi.biWidth][j]) * 0.118318
                          +  temp_rgb[i][j] * 0.147761;
            }
            else if (i > bi.biWidth * bi.biHeight - bi.biWidth)          //下边界除端点
            {
                rgb[i][j] = (temp_rgb[i-bi.biWidth-1][j] + temp_rgb[i-bi.biWidth+1][j] + temp_rgb[i-1][j] + temp_rgb[i+1][j]) * 0.0947416
                          + (temp_rgb[i-bi.biWidth][j] + temp_rgb[i-1][j] + temp_rgb[i+1][j]+ temp_rgb[i][j]) * 0.118318
                          +  temp_rgb[i][j] * 0.147761;
            }
            else if (i % bi.biWidth == 0)            //左边界除端点
            {
                rgb[i][j] = (temp_rgb[i-bi.biWidth][j] + temp_rgb[i-bi.biWidth+1][j] + temp_rgb[i+bi.biWidth][j] + temp_rgb[i+bi.biWidth+1][j]) * 0.0947416
                          + (temp_rgb[i-bi.biWidth][j] + temp_rgb[i][j] + temp_rgb[i+1][j]+ temp_rgb[i+bi.biWidth][j]) * 0.118318
                          +  temp_rgb[i][j] * 0.147761;
            }
            else if(i % bi.biWidth == bi.biWidth - 1)             //右边界除端点
            {
                rgb[i][j] = (temp_rgb[i-bi.biWidth-1][j] + temp_rgb[i-bi.biWidth][j] + temp_rgb[i+bi.biWidth-1][j] + temp_rgb[i+bi.biWidth][j]) * 0.0947416
                          + (temp_rgb[i-bi.biWidth][j] + temp_rgb[i-1][j] + temp_rgb[i][j]+ temp_rgb[i+bi.biWidth][j]) * 0.118318
                          +  temp_rgb[i][j] * 0.147761;
            }

            else
            {
                rgb[i][j] = (temp_rgb[i-bi.biWidth-1][j] + temp_rgb[i-bi.biWidth+1][j] + temp_rgb[i+bi.biWidth-1][j] + temp_rgb[i+bi.biWidth+1][j]) * 0.0947416
                          + (temp_rgb[i-bi.biWidth][j] + temp_rgb[i-1][j] + temp_rgb[i+1][j]+ temp_rgb[i+bi.biWidth][j]) * 0.118318
                          +  temp_rgb[i][j] * 0.147761;
            }
        }
    }
    delete[] temp_rgb;
}

void Bmp::Up_to_Down()
{
    uchar **temp_rgb = new uchar* [bi.biWidth * bi.biHeight];
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        temp_rgb[i] = new uchar[3];
    }
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        temp_rgb[i][0] = rgb[i][0];
        temp_rgb[i][1] = rgb[i][1];
        temp_rgb[i][2] = rgb[i][2];
    }

    for (int y = 0; y < bi.biHeight; y++)
    {
        for(int x = 0; x < bi.biWidth; x++)
        {
            for(int j = 0; j < 3; j++)
            {
                rgb[x + y * bi.biWidth][j] = temp_rgb[x + (bi.biHeight - y - 1) * bi.biWidth][j];
            }
        }
    }

    delete[] temp_rgb;
}

void Bmp::right_to_left()
{
    uchar **temp_rgb = new uchar* [bi.biWidth * bi.biHeight];
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        temp_rgb[i] = new uchar[3];
    }
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        temp_rgb[i][0] = rgb[i][0];
        temp_rgb[i][1] = rgb[i][1];
        temp_rgb[i][2] = rgb[i][2];
    }

    for (int y = 0; y < bi.biHeight; y++)
    {
        for(int x = 0; x < bi.biWidth; x++)
        {
            for(int j = 0; j < 3; j++)
            {
                rgb[x + y * bi.biWidth][j] = temp_rgb[bi.biWidth - x - 1 + y * bi.biWidth][j];
            }
        }
    }

    delete[] temp_rgb;
}

void Bmp::spin_90()
{
    uchar **temp_rgb = new uchar* [bi.biWidth * bi.biHeight];
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        temp_rgb[i] = new uchar[3];
    }
    for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
    {
        temp_rgb[i][0] = rgb[i][0];
        temp_rgb[i][1] = rgb[i][1];
        temp_rgb[i][2] = rgb[i][2];
    }

    long temp_biWidth = bi.biWidth;
    long temp_biHeight = bi.biHeight;

    bi.biWidth = temp_biHeight;
    bi.biHeight = temp_biWidth;

    for (int y = 0; y < temp_biHeight; y++)
    {
        for(int x = 0; x < temp_biWidth; x++)
        {
            for(int j = 0; j < 3; j++)
            {
                rgb[y + (bi.biHeight - x - 1) * bi.biWidth][j] = temp_rgb[x + y * temp_biWidth][j];
            }
        }
    }
}

void Bmp::zoom(int zoom_level)
{
    if (zoom_level == 0)
    {
        return;
    }

    else if (zoom_level > 0)
    {
        uchar **temp_rgb = new uchar* [bi.biWidth * bi.biHeight];
        for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
        {
            temp_rgb[i] = new uchar[3];
        }
        for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
        {
            temp_rgb[i][0] = rgb[i][0];
            temp_rgb[i][1] = rgb[i][1];
            temp_rgb[i][2] = rgb[i][2];
        }

        for (int i = 0; i < zoom_level; i++)
        {
            int times = 2;
            for (int m = 0; m < i; m++)
            {
                times *= 2;
            }
            for (int y = 0; y < bi.biHeight; y++)
            {
                for (int x = 0; x < bi.biWidth; x++)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        rgb[x + y * bi.biWidth][j] = temp_rgb[x / times + y / times * bi.biWidth][j];
                    }
                }
            }
        }
        delete [] temp_rgb;
    }

    else if (zoom_level < 0)
    {
        long temp_biWidth = bi.biWidth;
        uchar **temp_rgb = new uchar* [bi.biWidth * bi.biHeight];
        for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
        {
            temp_rgb[i] = new uchar[3];
        }
        for (int i = 0; i < bi.biWidth * bi.biHeight; i++)
        {
            temp_rgb[i][0] = rgb[i][0];
            temp_rgb[i][1] = rgb[i][1];
            temp_rgb[i][2] = rgb[i][2];
        }

        for (int i = zoom_level; i < 0; i++)
        {
            int multitimes = 2;
            for (int m = 0; m < (i - zoom_level); m++)
            {
                multitimes *= 2;
            }

            bi.biWidth /= 2;
            bi.biHeight /= 2;

            for (int y = 0; y < bi.biHeight; y++)
            {
                for (int x = 0; x < bi.biWidth; x++)
                {
                    for (int j = 0; j < 3; j++)
                    {
                        rgb[x + y * bi.biWidth][j] = temp_rgb[x * multitimes + y * multitimes * temp_biWidth][j];
                    }
                }
            }
        }

        delete [] temp_rgb;
    }
}

void Bmp::add_line_for_cut(int label_up, int label_down, int label_left, int label_right)
{
    int line_up = 0;
    int line_down = 0;
    int line_left = 0;
    int line_right = 0;

    if (label_up != 0)
    {
        line_left = bi.biWidth * label_up / 100;
    }
    if (label_down != 0)
    {
        line_right = bi.biWidth * label_down / 100;
    }
    if (label_left != 0)
    {
        line_up = bi.biHeight * label_left / 100;
    }
    if (label_right != 0)
    {
        line_down = bi.biHeight * label_right / 100;
    }

    for (int x = 0; x < bi.biWidth; x++)
    {
        for (int i = -1; i < 2; i++)
        {
            if ((line_up + i) >= 0 && (line_up + i) < bi.biHeight)
            {
                rgb[x + (line_up + i) * bi.biWidth][0] = 0;
                rgb[x + (line_up + i) * bi.biWidth][1] = 0;
                rgb[x + (line_up + i) * bi.biWidth][2] = 255;
            }
            if ((line_down + i) >= 0 && (line_down + i) < bi.biHeight)
            {
                rgb[x + (line_down + i) * bi.biWidth][0] = 0;
                rgb[x + (line_down + i) * bi.biWidth][1] = 0;
                rgb[x + (line_down + i) * bi.biWidth][2] = 255;
            }
        }

    }

    for (int y = 0; y < bi.biHeight; y++)
    {
        for (int i = -1; i < 2; i++)
        {
            if ((line_left + i) >= 0 && (line_left + i) < bi.biWidth)
            {
                rgb[line_left + i + y * bi.biWidth][0] = 0;
                rgb[line_left + i + y * bi.biWidth][1] = 0;
                rgb[line_left + i + y * bi.biWidth][2] = 255;
            }
            if ((line_right + i) >= 0 && (line_right + i) < bi.biWidth)
            {
                rgb[line_right + i + y * bi.biWidth][0] = 0;
                rgb[line_right + i + y * bi.biWidth][1] = 0;
                rgb[line_right + i + y * bi.biWidth][2] = 255;
            }
        }
    }
}

void Bmp::cut(int x1, int x2, int y1, int y2)
{
    int little_x = (x1 > x2 ? x2 : x1) * bi.biWidth / 100;
    int big_x = (x1 > x2 ? x1 : x2) * bi.biWidth / 100;
    int little_y = (y1 > y2 ? y2 : y1) * bi.biHeight /100;
    int big_y = (y1 > y2 ? y1 : y2) * bi.biHeight / 100;

    long new_biWidth = big_x - little_x;
    long new_biHeight = big_y - little_y;

    uchar **temp_rgb = new uchar* [new_biWidth * new_biHeight];
    for (int i = 0; i < new_biWidth * new_biHeight; i++)
    {
        temp_rgb[i] = new uchar[3];
    }
    for (int y = 0; y < new_biHeight; y++)
    {
        for (int x = 0; x < new_biWidth; x++)
        {
            for (int j = 0; j < 3; j++)
            {
                temp_rgb[x + y * new_biWidth][j] = rgb[little_x + little_y * bi.biWidth + x + y * bi.biWidth][j];
            }
        }
    }

    bi.biWidth = new_biWidth;
    bi.biHeight = new_biHeight;

    bi.biSizeImage = (bi.biWidth * bi.biBitCount + 31) / 32 * 4 * bi.biHeight;

    bf.bfSize = bf.bfOffBits + bi.biSizeImage;

    rgb = temp_rgb;
}


